home *** CD-ROM | disk | FTP | other *** search
/ Network CD 2 / Network CD - Volume 2.iso / programs / internet / tcp / amitcp / amitcp-src-22.lha / AmiTCP-2.2 / src / util / inetd / inetd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-20  |  42.7 KB  |  1,710 lines

  1. RCS_ID_C="$Id: inetd.c,v 1.11 1993/10/21 01:51:20 ppessi Exp $";
  2. /*
  3.  * inetd.c --- Internet super-server
  4.  *
  5.  * Author: ppessi <Pekka.Pessi@hut.fi>
  6.  *
  7.  * Copyright © 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
  8.  *                  Helsinki University of Technology, Finland.
  9.  *                  All rights reserved.
  10.  *
  11.  * Created      : Mon May 24 00:34:11 1993 ppessi
  12.  * Last modified: Thu Oct 21 03:51:03 1993 ppessi
  13.  *
  14.  * $Log: inetd.c,v $
  15.  * Revision 1.11  1993/10/21  01:51:20  ppessi
  16.  * Added correcto prototype for CheckIO()
  17.  *
  18.  * Revision 1.10  1993/10/20  05:31:07  ppessi
  19.  * Using now gettimeofday().
  20.  *
  21.  * Revision 1.9  1993/08/13  04:57:07  jraja
  22.  * Fixes for the second release.
  23.  *
  24.  * Revision 1.8  1993/08/10  20:46:23  jraja
  25.  * Added version string.
  26.  *
  27.  * Revision 1.7  1993/08/10  20:29:26  jraja
  28.  *  Added leap years to the time calculations (ppessi).
  29.  *
  30.  * Revision 1.6  1993/06/20  12:40:17  jraja
  31.  * Added SAVEDS to the start_builtin for it to be able to find SysBase.
  32.  *
  33.  * Revision 1.5  1993/06/04  11:44:19  jraja
  34.  * Fixes for the first release.
  35.  *
  36.  * Revision 1.4  93/06/03  20:11:51  ppessi
  37.  * Changed the daemon naming scheme, removed template from inetd.conf
  38.  * 
  39.  * Revision 1.3  93/05/28  20:11:48  ppessi
  40.  * Now works with CreateNewProc
  41.  * 
  42.  * Revision 1.2  93/05/25  23:07:35  ppessi
  43.  * Added external daemon launching
  44.  * 
  45.  * Revision 1.1  93/05/24  21:42:36  ppessi
  46.  * Original BSD code.
  47.  *
  48.  */
  49.  
  50. #include "inetd_rev.h"
  51. static const char version[] = VERSTAG;
  52.  
  53. char copyright[] =
  54. "@(#) Copyright © 1983 The Regents of the University of California.\n"
  55.                       "All rights reserved.\n"
  56.      "Copyright © 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>\n"
  57.                       "Helsinki University of Technology, Finland.\n"
  58.                       "All rights reserved.\n";
  59.  
  60. /*
  61.  * Copyright (c) 1983,1991 The Regents of the University of California.
  62.  * All rights reserved.
  63.  *
  64.  * Redistribution and use in source and binary forms, with or without
  65.  * modification, are permitted provided that the following conditions
  66.  * are met:
  67.  * 1. Redistributions of source code must retain the above copyright
  68.  *    notice, this list of conditions and the following disclaimer.
  69.  * 2. Redistributions in binary form must reproduce the above copyright
  70.  *    notice, this list of conditions and the following disclaimer in the
  71.  *    documentation and/or other materials provided with the distribution.
  72.  * 3. All advertising materials mentioning features or use of this software
  73.  *    must display the following acknowledgement:
  74.  *    This product includes software developed by the University of
  75.  *    California, Berkeley and its contributors.
  76.  * 4. Neither the name of the University nor the names of its contributors
  77.  *    may be used to endorse or promote products derived from this software
  78.  *    without specific prior written permission.
  79.  *
  80.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  81.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  82.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  83.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  84.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  85.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  86.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  87.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  88.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  89.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  90.  * SUCH DAMAGE.
  91.  */
  92.  
  93. /****** netutil.doc/inetd ***************************************************
  94. *
  95. *  NAME
  96. *        inetd - internet ``super-server''
  97. *
  98. *  TEMPLATE
  99. *       inetd DEBUG/S CONFIGFILE
  100. *
  101. *  DESCRIPTION
  102. *
  103. *       Inetd should be run when the AmiTCP/IP protocol stack is started.
  104. *       Inetd listens for connections on certain internet sockets.  When a
  105. *       connection is found on one of its sockets, it decides what service the
  106. *       socket corresponds to, and invokes a program to service the request.
  107. *       After the program is finished, it continues to listen on the socket
  108. *       (except in some cases which will be described below).  Essentially,
  109. *       inetd allows running one daemon to invoke several others, reducing
  110. *       load on the system.
  111. *
  112. *  PARAMETERS
  113. *       DEBUG      Turns on debugging.
  114. *
  115. *       CONFIGFILE Specifies the configuration file name.
  116. *
  117. *  CONFIGURATION
  118. *
  119. *       Upon execution, inetd reads its configuration information from a
  120. *       configuration file which, by default, is AmiTCP:db/inetd.conf. There
  121. *       must be an entry for each field of the configuration file, with
  122. *       entries for each field separated by a tab or a space.  Comments are
  123. *       denoted by a ``#'' at the beginning of a line or ``;'' anywhere in the
  124. *       line. There must be an entry for each field. The fields of the
  125. *       configuration file are as follows:
  126. *
  127. *             service name
  128. *             socket type
  129. *             protocol
  130. *             wait/nowait
  131. *             user
  132. *             server program
  133. *             server program name
  134. *             server program arguments
  135. *
  136. *       The service-name entry is the name of a valid service in the
  137. *       netdatabase.  For ``internal'' services (discussed below), the service
  138. *       name must be the official name of the service.
  139. *
  140. *       The socket-type should be one of ``stream'', ``dgram'', ``raw'',
  141. *       ``rdm'', or ``seqpacket'', depending on whether the socket is a
  142. *       stream, datagram, raw, reliably delivered message, or sequenced packet
  143. *       socket. Current system supports only stream, datagram and raw
  144. *       protocols.
  145. *
  146. *       The protocol must be a valid protocol as given in netdatabase.
  147. *       Examples might be ``tcp'' or ``udp''.
  148. *
  149. *       The wait/nowait entry is useful for datagram sockets only (other
  150. *       sockets should have a ``nowait'' entry in this space).  If a datagram
  151. *       server connects to its peer, freeing the socket so inetd can received
  152. *       further messages on the socket, it is said to be a ``multi-threaded''
  153. *       server, and should use the ``nowait'' entry.  For datagram servers
  154. *       which process all incoming datagrams on a socket and eventually time
  155. *       out, the server is said to be ``single-threaded'' and should use a
  156. *       ``wait'' entry.  Comsat and talkd are both examples of the latter type
  157. *       of datagram server.
  158. *
  159. *       The user entry should contain the user name of the user as whom the
  160. *       server should run. This field is for Unix and future compability
  161. *       only.
  162. *
  163. *       The server-program entry should contain the pathname of the program
  164. *       which is to be executed by inetd when a request is found on its
  165. *       socket.  If the server program is resident, the path name should be
  166. *       suppressed. If inetd provides this service internally, this entry
  167. *       should be ``internal''.
  168. *
  169. *       The server-program-name is CLI command name for the server process. It
  170. *       is shown in the printout of ``status'' command. (Task name of the
  171. *       server process is the service and the peer address, e.g. ``echo
  172. *       [192.233.15.19]''.) This and argument entry are optional.
  173. *
  174. *       The server program arguments should be just as arguments normally are.
  175. *
  176. *       Inetd provides several ``trivial'' services internally by use of
  177. *       routines within itself.  These services are ``echo'', ``discard'',
  178. *       ``chargen'' (character generator), ``daytime'' (human readable time),
  179. *       and ``time'' (machine readable time, in the form of the number of
  180. *       seconds since mid­ night, January 1, 1900).  All of these services are
  181. *       TCP and UDP based.  For details of these services, consult the
  182. *       appropriate RFC from the Network Information Center.
  183. *
  184. *       Inetd rereads its configuration file when it receives the CTRL-F
  185. *       signal.  Services may be added, deleted or modified when the
  186. *       configuration file is reread.
  187. *
  188. *  HISTORY
  189. *       The inetd command appeared in 4.3BSD system.
  190. *
  191. *  SEE ALSO
  192. *
  193. *****************************************************************************
  194. *
  195. */
  196.  
  197. /*
  198.  * Inetd - Internet super-server
  199.  *
  200.  * This program invokes all internet services as needed.
  201.  * connection-oriented services are invoked each time a connection is
  202.  * made, by creating a process. Created server process is passed the
  203.  * connection as file descriptor 0 and is expected to do a getpeername
  204.  * to find out the source host and port.
  205.  *
  206.  * Datagram oriented services are invoked when a datagram arrives; a
  207.  * process is created and passed a pending message on file descriptor
  208.  * 0. Datagram servers may either connect to their peer, freeing up
  209.  * the original socket for inetd to receive further messages on, or
  210.  * ``take over the socket'', processing all arriving datagrams and,
  211.  * eventually, timing out. The first type of server is said to
  212.  * be ``multi-threaded''; the second type of server
  213.  * ``single-threaded''.
  214.  *
  215.  * Inetd uses a configuration file which is read at startup and,
  216.  * possibly, at some later time in response to a signal CTRL_F.  The
  217.  * configuration file is parsed with standard DOS functions with
  218.  * template given below. Multiple line entries must have a ``+'' char at
  219.  * the end of the file.
  220.  *
  221.  *     service             must be in /etc/services
  222.  *    socket type            stream/dgram/raw/rdm/seqpacket
  223.  *    protocol            must be in /etc/protocols
  224.  *    dowait                    single-threaded/multi-threaded
  225.  *    user                user to run daemon as
  226.  *    server program            full path name
  227.  *    server program name        CLI command name (optional)
  228.  *    server program arguments    Normal command argument line 
  229.  *
  230.  * Comment lines are indicated by a `#' in column 1. 
  231.  */
  232.  
  233. #include <sys/param.h>
  234. #include <sys/stat.h>
  235. #include <sys/ioctl.h>
  236. #include <sys/socket.h>
  237. #include <sys/time.h>
  238.  
  239. #include <netinet/in.h>
  240. #include <arpa/inet.h>
  241.  
  242. #include <errno.h>
  243. #include <signal.h>
  244. #include <netdb.h>
  245. #include <stdio.h>
  246. #include <string.h>
  247. #include <stdlib.h>
  248. #include <time.h>
  249.  
  250. #ifdef AMIGA
  251. #include <exec/execbase.h>
  252. #include <exec/memory.h>
  253. #include <devices/timer.h>
  254. #include <dos/dostags.h>
  255. extern struct ExecBase *SysBase;
  256. #if __SASC
  257. #include <proto/socket.h>
  258. #include <proto/dos.h>
  259. #include <clib/exec_protos.h>
  260. #include <pragmas/exec_sysbase_pragmas.h>
  261. #include <pragmas/timer_pragmas.h>
  262. /* #elif __GNUC__
  263. #include <inline/socket.h>
  264. #include <inline/exec.h>
  265. */
  266. #else 
  267. #error Unsupported compiler
  268. #include <clib/socket_protos.h>
  269. #endif
  270. #include <sys/syslog.h>
  271. /* Correct prototype for the CheckIO.
  272.  * (The one in clib/exec_protos.h has wrong return value type: BOOL (16 bits) 
  273.  * instead of a pointer (32 bits)!)
  274.  */
  275. struct IORequest * CheckIO(struct IORequest *req);
  276. #else /* def AMIGA */
  277. #include <pwd.h>
  278. #include <sys/file.h>
  279. #include <sys/wait.h>
  280. #include <sys/resource.h>
  281. #include <syslog.h>
  282. #endif
  283.  
  284. /* Compiler specific definitions */
  285. #if __GNUC__
  286. #define SAVEDS
  287. #define REG(X)
  288. #define ASM
  289. #elif __SASC
  290. #define SAVEDS __saveds
  291. #define REG(X) register __ ## X
  292. #define ASM    __asm
  293. #else
  294. #define SAVEDS
  295. #endif
  296.  
  297. #include "inetd.h"
  298. #include "inetdlib.h"
  299.  
  300. /* don't start more than TOOMANY servers in CNT_INTVL seconds */
  301. #define    TOOMANY        10
  302. #define    CNT_INTVL    60        
  303.  
  304. #define    RETRYTIME    (60*10)        /* retry after bind or server fail */
  305.  
  306. #define INETDNAME "inetd"
  307.  
  308. #define MAXARGS 9
  309. enum fileargs 
  310.   service = 0, socket_type, protocol, wait, user, server, cmdname, arguments
  311. };
  312. #define TYPETEMPLATE "stream,dgram,raw,rdm,seqpacket"
  313. #define WAITTEMPLATE "nowait,wait"
  314.  
  315. extern    int errno;
  316.  
  317. void reapchild(void);
  318. void startserver(register struct servtab *sep, long ctrl);
  319. void askalarm(long seconds);
  320. void getalarm(void);
  321. void config(void);
  322. void retry(void);
  323. void setup(register struct servtab *sep);
  324. struct servtab *enter(struct servtab *cp);
  325.  
  326. int setconfig(void);
  327. struct servtab *getconfigent(void);
  328. void freeconfig(register struct servtab *cp);
  329. void endconfig(void);
  330. void print_service(char *action, struct servtab *sep);
  331.  
  332. ASM VOID exitcode(REG(d0) LONG status, REG(d1) LONG exitmessage);
  333. LONG start_builtin(void);
  334. void setproctitle(char *a, int s);
  335.  
  336. UBYTE *proctitle(char *a, int s);
  337. void  amigainit(void);
  338. void amigadeinit(void);
  339. static ULONG csprintf(struct CSource *buf, const char *fmt, ...);
  340.  
  341. int    nsock = 0, maxsock = 0;
  342. fd_set    allsock;
  343. int    options = 0;
  344. struct    servent *sp = NULL;
  345.  
  346. /* 
  347.  * We create a "process table" for builtins, because they 
  348.  * must be waited as they use the same code segment as we do 
  349.  */
  350. #define MAX_BUILTIN_PROC 16
  351. int builtins_started = 0;
  352. long ptable[MAX_BUILTIN_PROC] = { 0 };
  353.  
  354. struct DaemonPort *dport = NULL;
  355.  
  356. #define DO_WAIT   ((struct DaemonMessage *)1)
  357. #define DONT_WAIT ((struct DaemonMessage *)NULL)
  358.  
  359. struct MsgPort *tport = NULL;
  360. struct timerequest *tmsg = NULL;
  361. int   timer_is_open = 0;
  362. #define TimerBase (tmsg->tr_node.io_Device)
  363.  
  364. struct    servtab {
  365.     char    *se_service;        /* name of service */
  366.     long    se_socktype;        /* type of socket to use */
  367.     char    *se_proto;        /* protocol used */
  368.     struct     DaemonMessage *se_wait; /* single threaded server */
  369.     char    *se_user;        /* user name to run as */
  370.     struct    biltin *se_bi;        /* if built-in, description */
  371.     char    *se_server;        /* server program */
  372.     char    *se_argv0;            /* cli name for daemon */
  373.     char    *se_argv;            /* program arguments */
  374.     long    se_fd;            /* open descriptor */
  375.     struct    sockaddr_in se_ctrladdr;/* bound address */
  376.     struct    timeval se_time;    /* start of se_count */
  377.     struct    servtab *se_next;
  378.     short    se_checked;        /* looked at during merge */
  379.     short    se_count;        /* number started since se_time */
  380. } *servtab;
  381.  
  382. /* 
  383.  * Internal Services 
  384.  *
  385.  * Because Data Segment is *not* duplicated by CreateNewProc 
  386.  * server routines must be re-entrable and not touch global data
  387.  */ 
  388. int echo_stream(void *SocketBase, int s, struct servtab *sep);
  389. int echo_dg(void *SocketBase, int s, struct servtab *sep);
  390. int discard_stream(void *SocketBase, int s, struct servtab *sep);
  391. int discard_dg(void *SocketBase, int s, struct servtab *sep); 
  392. int machtime_stream(void *SocketBase, int s, struct servtab *sep);
  393. int machtime_dg(void *SocketBase, int s, struct servtab *sep); 
  394. int daytime_stream(void *SocketBase, int s, struct servtab *sep);
  395. int daytime_dg(void *SocketBase, int s, struct servtab *sep);
  396. int chargen_stream(void *SocketBase, int s, struct servtab *sep);
  397. int chargen_dg(void *SocketBase, int s, struct servtab *sep);
  398.  
  399. struct biltin {
  400.     char    *bi_service;        /* internally provided service name */
  401.     int    bi_socktype;        /* type of socket supported */
  402.     int    bi_process;        /* 1 if should start a process */
  403.     struct    DaemonMessage *bi_wait;    /* DO_WAIT if should wait for child */
  404.     int    (*bi_fn)(void *SocketBase, int s, struct servtab *sep);
  405.                         /* function which performs it */
  406. } biltins[] = {
  407.     /* Echo received data */
  408.     "echo",        SOCK_STREAM,    1, DONT_WAIT,    echo_stream,
  409.     "echo",        SOCK_DGRAM,    0, DONT_WAIT,    echo_dg,
  410.  
  411.     /* Internet /dev/null */
  412.     "discard",    SOCK_STREAM,    1, DONT_WAIT,    discard_stream,
  413.     "discard",    SOCK_DGRAM,    0, DONT_WAIT,    discard_dg,
  414.  
  415.     /* Return 32 bit time since 1970 */
  416.     "time",        SOCK_STREAM,    0, DONT_WAIT,    machtime_stream,
  417.     "time",        SOCK_DGRAM,    0, DONT_WAIT,    machtime_dg,
  418.  
  419.     /* Return human-readable time */
  420.     "daytime",    SOCK_STREAM,    0, DONT_WAIT,    daytime_stream,
  421.     "daytime",    SOCK_DGRAM,    0, DONT_WAIT,    daytime_dg,
  422.  
  423.     /* Familiar character generator */
  424.     "chargen",    SOCK_STREAM,    1, DONT_WAIT,    chargen_stream,
  425.     "chargen",    SOCK_DGRAM,    0, DONT_WAIT,    chargen_dg,
  426.     0
  427. };
  428.  
  429. /* Internal buffer size. Allocated from stack */
  430. #define    BUFSIZE    8192
  431.  
  432. #define NUMINT    (sizeof(intab) / sizeof(struct inent))
  433.  
  434. int debug;
  435. char *CONFIG = _PATH_INETDCONF;
  436.  
  437. main(void)
  438. {
  439.   register struct servtab *sep;
  440.   ULONG events;
  441.   ULONG mask;
  442.  
  443.   {
  444.     LONG Argv[2];
  445.     struct RDArgs *rdargs;
  446.  
  447.     Argv[0] = Argv[1] = 0;
  448.     rdargs = ReadArgs("DEBUG/S,CONFIGFILE", Argv, NULL);
  449.  
  450.     if (!rdargs) {
  451.       PrintFault(IoErr(), "ReadArgs");
  452.       exit(1);
  453.     }
  454.     debug = Argv[0];
  455.     if (Argv[1])
  456.       CONFIG = strdup((char *)Argv[1]);
  457.  
  458.     FreeArgs(rdargs);
  459.   }
  460.  
  461.   if (debug) {
  462.     options |= SO_DEBUG;
  463.   } else {
  464. #if 0
  465.     daemon(0, 0);
  466. #endif
  467.   }
  468. #ifdef notyet
  469.   openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
  470. #endif
  471.  
  472.   amigainit();
  473.  
  474.   events = 1 << (dport->dp_Port.mp_SigBit) | 1 << (tport->mp_SigBit) 
  475.     | SIGBREAKF_CTRL_F | SIGBREAKF_CTRL_C;
  476.   SetSocketSignals(0L, 0L, 0L); /* no no no no no no there is no EINTR */
  477.  
  478.   config();
  479.  
  480.   for (;;) {
  481.     int n, ctrl;
  482.     fd_set readable;
  483.  
  484.     mask = events;
  485.     readable = allsock;
  486.     if ((n = WaitSelect(maxsock + 1, &readable, (fd_set *)NULL,
  487.             (fd_set *)NULL, (struct timeval *)NULL, &mask)) < 0) {
  488.       if (errno != EINTR)
  489.     syslog(LOG_WARNING, "select: %s", strerror(errno));
  490.       continue;
  491.     }
  492.  
  493.     if (mask & SIGBREAKF_CTRL_F) {
  494.       config();
  495.     }
  496.  
  497.     if (mask & SIGBREAKF_CTRL_C) {
  498.       exit(0);
  499.     }
  500.  
  501.     if (mask & (1<<(tport->mp_SigBit))) {
  502.       getalarm();
  503.     }
  504.  
  505.     if (mask & (1<<(dport->dp_Port.mp_SigBit))) {
  506.       reapchild();
  507.     }
  508.  
  509.     for (sep = servtab; n && sep; sep = sep->se_next)
  510.       if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
  511.     n--;
  512.     if (debug)
  513.       fprintf(stderr, "someone wants %s\n", sep->se_service);
  514.     if (sep->se_socktype == SOCK_STREAM) {
  515.       ctrl = accept(sep->se_fd, NULL, NULL);
  516.       if (debug)
  517.         fprintf(stderr, "accept, ctrl %ld\n", ctrl);
  518.       if (ctrl < 0) {
  519.         if (errno != EINTR)
  520.           syslog(LOG_WARNING, "accept (for %s): %s", 
  521.              sep->se_service, strerror(errno));
  522.         continue;
  523.       }
  524.     } else
  525.       ctrl = sep->se_fd;
  526.     if (sep->se_bi == 0 || sep->se_bi->bi_process) {
  527.       startserver(sep, ctrl);
  528.     } else {
  529.       (*sep->se_bi->bi_fn)(SocketBase, ctrl, sep);
  530.       if (sep->se_socktype == SOCK_STREAM)
  531.         CloseSocket(ctrl);
  532.     }
  533.       }
  534.   }
  535. }
  536.  
  537. /*
  538.  * startserver:
  539.  *      Launch a new process to handle service
  540.  */
  541. void 
  542. startserver( register struct servtab *sep, long ctrl)
  543. {
  544.   LONG id;
  545.   struct DaemonMessage *dm = CreateIORequest(dport, sizeof(*dm));
  546.   UBYTE *dname = proctitle(sep->se_service, ctrl);
  547.   int ok = 0;
  548.  
  549.   if (!dm || !dname) { 
  550.     syslog(LOG_ERR, "inetd exhausted memory, exits");
  551.     if (dm) DeleteIORequest(dm);
  552.     if (dname) FreeVec(dname);
  553.     exit(1);
  554.   }
  555.  
  556.   if (sep->se_count++ == 0) {
  557.     (void)gettimeofday(&sep->se_time, (struct timezone *)0);
  558.   } else if (sep->se_count >= TOOMANY) {
  559.     struct timeval now;
  560.     (void)gettimeofday(&now, (struct timezone *)0);
  561.     if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) {
  562.       sep->se_time = now;
  563.       sep->se_count = 1;
  564.     } else {
  565.       syslog(LOG_ERR, "%s/%s server failing (looping), "
  566.          "service terminated\n", sep->se_service, sep->se_proto);
  567.       FD_CLR(sep->se_fd, &allsock);
  568.       (void) CloseSocket(sep->se_fd);
  569.       sep->se_fd = -1;
  570.       sep->se_count = 0;
  571.       nsock--;
  572.       askalarm(RETRYTIME);
  573.     }
  574.   }
  575.  
  576.   if (sep->se_socktype == SOCK_STREAM)
  577.     id = ReleaseSocket(ctrl, -1);
  578.   else
  579.     id = ReleaseCopyOfSocket(ctrl, -1);
  580.  
  581.   if (dm != NULL && id != -1) {
  582.     dm->dm_Msg.mn_Node.ln_Name = dname;
  583.     dm->dm_Id = id;
  584.     dm->dm_Family = AF_INET;
  585.     dm->dm_Type = sep->se_socktype;
  586.  
  587.     if (sep->se_bi) {
  588.       struct Process *pid = NULL;
  589.       /* 
  590.        * Start a built in function
  591.        */
  592.       dm->dm_Retval = (LONG)sep;
  593.       dm->dm_Type = DMTYPE_INTERNAL;
  594.       if (builtins_started < MAX_BUILTIN_PROC) {
  595.     pid =
  596.       CreateNewProcTags(NP_Entry, start_builtin, NP_StackSize, BUFSIZE*2,
  597.                 NP_ExitCode, exitcode, NP_ExitData, dm,
  598.                 NP_Priority, -10,
  599.                 dname ? NP_Name : TAG_DONE, dname,
  600.                 TAG_DONE);
  601.     ok = pid != NULL;
  602.     if (ok) {
  603.       dm->dm_Pid = pid; 
  604.       ptable[builtins_started++] = (long)pid;
  605.     }
  606.       }
  607.     } else {
  608.       /*
  609.        * Start an external process
  610.        */
  611.       BPTR input = Open("NIL:", MODE_OLDFILE);
  612.       BPTR output = Open("NIL:", MODE_OLDFILE);
  613. #if 1
  614.       BPTR seglist;
  615.       struct Segment *sl;
  616.  
  617.       /* Try to find seglist from resident list */
  618.       Forbid();
  619.       if (sl = FindSegment(sep->se_server, NULL, FALSE)) {
  620.     if (sl->seg_UC >= 0) {
  621.       sl->seg_UC++;
  622.       dm->dm_Seg = sl;        /* must be freed */
  623.     } else if (sl->seg_UC != -2) {
  624.       sl = NULL;
  625.     }
  626.       }
  627.       Permit();
  628.  
  629.       if (sl)
  630.     seglist = sl->seg_Seg;
  631.       else
  632.     seglist = NewLoadSegTags(sep->se_server, TAG_DONE);
  633.  
  634.       if (input && output && seglist) {
  635.     ok = (int)
  636.       CreateNewProcTags(NP_Seglist, seglist,
  637.                 NP_FreeSeglist, sl == NULL,
  638.                 NP_Cli, TRUE, 
  639.                 NP_CommandName, sep->se_argv0,
  640.                 NP_Arguments, sep->se_argv, 
  641.                 NP_Input, input, 
  642.                 NP_Output, output,
  643.                 NP_StackSize, BUFSIZE*2, 
  644.                 NP_Priority, -10, 
  645.                 NP_ExitCode, dport->dp_ExitCode,
  646.                 NP_ExitData, dm, 
  647.                 dname ? NP_Name : TAG_END, dname,
  648.                 TAG_END, NULL);
  649.       }
  650.       if (!ok) {
  651.     if (seglist) UnLoadSeg(seglist);
  652.     if (input) Close(input);
  653.     if (output) Close(output);
  654.       }
  655.     }
  656. #else
  657.       if (input && output) {
  658.     ok = !SystemTags(sep->se_argv,
  659.              SYS_Asynch, 1, SYS_UserShell, 1,
  660.              SYS_Input, input, SYS_Output, output,
  661.              NP_StackSize, BUFSIZE*2,
  662.              NP_ExitCode, exitcode, NP_ExitData, dm,
  663.              NP_Priority, -10, 
  664.              dname ? NP_Name : TAG_END, dname,
  665.              TAG_END, NULL);
  666.       }
  667.       if (!ok) {
  668.     if (input) Close(input);
  669.     if (output) Close(output);
  670.       }
  671.     }
  672. #endif
  673.     if (ok && sep->se_wait) {
  674.       sep->se_wait = dm;
  675.       if (sep->se_fd >= 0) {
  676.     FD_CLR(sep->se_fd, &allsock);
  677.     nsock--;
  678.       }
  679.     }
  680.   }
  681.  
  682.   /* Clean up */
  683.   if (!ok) {
  684.     /* Drop the pending datagram */
  685.     char buf[32];
  686.     if (sep->se_socktype != SOCK_STREAM)
  687.       recv(ctrl, buf, sizeof (buf), 0);
  688.  
  689.     if (dm) DeleteIORequest(dm);
  690.     if (dname) FreeVec(dname);
  691.     if (id != -1) {
  692.       ctrl = ObtainSocket(id, AF_INET, sep->se_socktype, 0);
  693.       if (ctrl >= 0) CloseSocket(ctrl);
  694.     }
  695.   }
  696. }
  697.  
  698. /*
  699.  * reapchild: 
  700.  *      handle death messages from childs
  701.  */
  702. void
  703. reapchild(void)
  704. {
  705.   struct DaemonMessage *dm;
  706.  
  707.   while (dm = (struct DaemonMessage *)GetMsg(dport)) {
  708.     long status = dm->dm_Retval;
  709.     register struct servtab *sep;
  710.  
  711.     if (debug)
  712.       fprintf(stderr, "reaped child %s\n", dm->dm_Msg.mn_Node.ln_Name);
  713.     for (sep = servtab; sep; sep = sep->se_next)
  714.       if (sep->se_wait == dm) {
  715.     if (status)
  716.       syslog(LOG_WARNING,
  717.          "%s: exit status 0x%lx",
  718.          sep->se_server, status);
  719.     if (debug)
  720.       fprintf(stderr, "restored %s, fd %ld\n",
  721.           sep->se_service, sep->se_fd);
  722.     FD_SET(sep->se_fd, &allsock);
  723.     nsock++;
  724.     sep->se_wait = DO_WAIT;
  725.       }
  726.  
  727.     /* update "process table" */ 
  728.     if (dm->dm_Type == DMTYPE_INTERNAL) {
  729.       long pid = (long)dm->dm_Pid;
  730.       int i = --builtins_started;
  731.       for (i; i >= 0; i--) 
  732.     if (pid = ptable[i]) {
  733.       ptable[i] = ptable[builtins_started];
  734.       break;
  735.     }
  736.       if (i < 0) {
  737.     syslog(LOG_ALERT, "inetd: unknown internal daemon 0x%lx", pid);
  738.     builtins_started++;
  739.       }
  740.     }
  741.     /* Free resources allocated for the daemon */
  742.     if (dm->dm_Seg) {
  743.       Forbid();
  744.       dm->dm_Seg->seg_UC--;
  745.       Permit();
  746.     }
  747.     if (dm->dm_Msg.mn_Node.ln_Name)
  748.       FreeVec(dm->dm_Msg.mn_Node.ln_Name);
  749.     DeleteIORequest(dm);
  750.   }
  751. }
  752.  
  753. /*
  754.  * config:
  755.  *      configure services
  756.  */
  757. void
  758. config(void)
  759. {
  760.   register struct servtab *sep, *cp, **sepp;
  761.  
  762.   if (!setconfig()) {
  763.     endconfig();
  764.     return;
  765.   }
  766.  
  767.   for (sep = servtab; sep; sep = sep->se_next)
  768.     sep->se_checked = 0;
  769.   while (cp = getconfigent()) {
  770.     for (sep = servtab; sep; sep = sep->se_next)
  771.       if (strcmp(sep->se_service, cp->se_service) == 0 &&
  772.       strcmp(sep->se_proto, cp->se_proto) == 0)
  773.     break;
  774.     if (sep != 0) {
  775.       freeconfig(sep);
  776.       /*
  777.        * sep->se_wait may be holding the "pid" of a daemon
  778.        * that we're waiting for.  If so, don't overwrite
  779.        * it unless the config file explicitly says don't 
  780.        * wait.
  781.        */
  782.       if (cp->se_bi == 0 && 
  783.       (sep->se_wait == DO_WAIT || cp->se_wait == DONT_WAIT))
  784.     sep->se_wait  = cp->se_wait;
  785.       sep->se_service = cp->se_service;
  786.       sep->se_proto   = cp->se_proto;
  787.       sep->se_user    = cp->se_user;
  788.       sep->se_server  = cp->se_server;
  789.       sep->se_argv    = cp->se_argv;
  790.       if (debug)
  791.     print_service("REDO", sep);
  792.     } else {
  793.       sep = enter(cp);
  794.       if (debug)
  795.     print_service("ADD ", sep);
  796.     }
  797.     sep->se_checked = 1;
  798.     sp = getservbyname(sep->se_service, sep->se_proto);
  799.     if (sp == 0) {
  800.       syslog(LOG_ERR, "%s/%s: unknown service",
  801.          sep->se_service, sep->se_proto);
  802.       if (sep->se_fd != -1)
  803.     (void) CloseSocket(sep->se_fd);
  804.       sep->se_fd = -1;
  805.       continue;
  806.     }
  807.     if (sp->s_port != sep->se_ctrladdr.sin_port) {
  808.       sep->se_ctrladdr.sin_port = sp->s_port;
  809.       if (sep->se_fd != -1)
  810.     (void) CloseSocket(sep->se_fd);
  811.       sep->se_fd = -1;
  812.     }
  813.     if (sep->se_fd == -1)
  814.       setup(sep);
  815.   }
  816.   endconfig();
  817.   /*
  818.    * Purge anything not looked at above.
  819.    */
  820.   sepp = &servtab;
  821.   while (sep = *sepp) {
  822.     if (sep->se_checked) {
  823.       sepp = &sep->se_next;
  824.       continue;
  825.     }
  826.     *sepp = sep->se_next;
  827.     if (sep->se_fd != -1) {
  828.       FD_CLR(sep->se_fd, &allsock);
  829.       nsock--;
  830.       (void) CloseSocket(sep->se_fd);
  831.     }
  832.     if (debug)
  833.       print_service("FREE", sep);
  834.     freeconfig(sep);
  835.     free((char *)sep);
  836.   }
  837. }
  838.  
  839. /*
  840.  * askalarm:
  841.  *      ask for timeout
  842.  */
  843. void 
  844. askalarm(long seconds) 
  845. {
  846.   if (tmsg->tr_node.io_Message.mn_Node.ln_Type == NT_UNKNOWN 
  847.       || CheckIO(tmsg)) {
  848.     tmsg->tr_time.tv_secs = seconds;
  849.     tmsg->tr_time.tv_micro = 0;
  850.     SendIO(tmsg);
  851.   }
  852. }
  853.  
  854. /*
  855.  * getalarm:
  856.  *      handle timeouts
  857.  */
  858. void 
  859. getalarm(void) 
  860. {
  861.   struct Message *msg;
  862.   while (msg = GetMsg(tport)) {
  863.     if ((struct timerequest *)msg == tmsg) {
  864.       tmsg->tr_node.io_Message.mn_Node.ln_Type = NT_UNKNOWN; 
  865.       retry();
  866.       continue;
  867.     }
  868.   }
  869. }
  870.  
  871. /*
  872.  * retry:
  873.  *      try to setup all configured services
  874.  */
  875. void
  876. retry(void)
  877. {
  878.   register struct servtab *sep;
  879.  
  880.   for (sep = servtab; sep; sep = sep->se_next)
  881.     if (sep->se_fd == -1)
  882.       setup(sep);
  883. }
  884.  
  885. /*
  886.  * setup:
  887.  *      open a socket for given port
  888.  */
  889. void
  890. setup(register struct servtab *sep)
  891. {
  892.   int on = 1;
  893.  
  894.   if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
  895.     syslog(LOG_ERR, "%s/%s: socket: %s",
  896.        sep->se_service, sep->se_proto, strerror(errno));
  897.     return;
  898.   }
  899. #define    turnon(fd, opt) \
  900.   setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
  901.     if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
  902.     turnon(sep->se_fd, SO_DEBUG) < 0)
  903.       syslog(LOG_ERR, "setsockopt (SO_DEBUG): %s", strerror(errno));
  904.   if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
  905.     syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %s", strerror(errno));
  906. #undef turnon
  907.   if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
  908.        sizeof (sep->se_ctrladdr)) < 0) {
  909.     syslog(LOG_ERR, "%s/%s: bind: %s",
  910.        sep->se_service, sep->se_proto, strerror(errno));
  911.     (void) CloseSocket(sep->se_fd);
  912.     sep->se_fd = -1;
  913.     askalarm(RETRYTIME);
  914.     return;
  915.   }
  916.   if (sep->se_socktype == SOCK_STREAM)
  917.     listen(sep->se_fd, 10);
  918.   FD_SET(sep->se_fd, &allsock);
  919.   nsock++;
  920.   if (sep->se_fd > maxsock)
  921.     maxsock = sep->se_fd;
  922. }
  923.  
  924. /*
  925.  * enter:
  926.  *      Allocate a new server entry
  927.  */ 
  928. struct servtab *
  929. enter(struct servtab *cp)
  930. {
  931.   register struct servtab *sep;
  932.  
  933.   sep = (struct servtab *)malloc(sizeof (*sep));
  934.   if (sep == (struct servtab *)0) {
  935.     syslog(LOG_ERR, "Out of memory.");
  936.     exit(20);
  937.   }
  938.   *sep = *cp;
  939.   sep->se_fd = -1;
  940.   sep->se_next = servtab;
  941.   servtab = sep;
  942.  
  943.   return (sep);
  944. }
  945.  
  946. /*
  947.  * print_service:
  948.  *    Dump relevant information to stderr
  949.  */
  950. void
  951. print_service(char *action, struct servtab *sep)
  952. {
  953.   fprintf(stderr, "%s: %s proto=%s, "
  954.       "wait=%ld, user=%s builtin=0x%lx server=%s\n",
  955.       action, sep->se_service, sep->se_proto,
  956.       sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server);
  957. }
  958.  
  959.  
  960. /* 
  961.  * Functions to read configuration file
  962.  */
  963.  
  964. BPTR    fconfig = NULL;
  965. long    linecnt = 0;
  966. struct    servtab serv;
  967. #define LINEBUFLEN 1024
  968. char    *linbuf = NULL;
  969. struct  CSource    line = { 0, 0, 0 };
  970. struct RDArgs *largs = NULL;
  971.  
  972. void logdoserror(const char *banner);
  973. struct CSource * nextline(BPTR fh);
  974.  
  975. int
  976. setconfig(void)
  977. {
  978.   linecnt = 0;
  979.  
  980.   if (!linbuf) 
  981.     linbuf = malloc(LINEBUFLEN);
  982.  
  983.   if (!largs) 
  984.     largs = AllocDosObject(DOS_RDARGS, NULL);
  985.  
  986.   if (fconfig != NULL) {
  987.     Seek(fconfig, 0L, OFFSET_BEGINNING);
  988.   } else {
  989.     fconfig = Open(CONFIG, MODE_OLDFILE);
  990.     if (!fconfig) logdoserror("setconfig");
  991.   }
  992.   return (fconfig != NULL && linbuf != NULL && largs != NULL);
  993. }
  994.  
  995. void
  996. endconfig(void)
  997. {
  998.   if (fconfig) {
  999.     (void) Close(fconfig);
  1000.     fconfig = NULL;
  1001.   }
  1002. #if 0
  1003.   if (linbuf) {
  1004.     free(linbuf);
  1005.     linbuf = NULL;
  1006.   }
  1007. #endif
  1008.   if (largs) {
  1009.     FreeDosObject(DOS_RDARGS, largs);
  1010.     largs = NULL;
  1011.   }
  1012. }
  1013.  
  1014. struct servtab *
  1015. getconfigent(void)
  1016. {
  1017.   register struct servtab *sep = &serv;
  1018.   struct CSource *cp;
  1019.  
  1020.  more:
  1021.   while ((cp = nextline(fconfig)) && 
  1022.      (cp->CS_Buffer[0] == '#' || cp->CS_Buffer[0] == ';'))
  1023.     ;
  1024.   if (cp == NULL)
  1025.     return NULL;
  1026.  
  1027.   {
  1028.     short len, i, item;
  1029.     char *old, *new; 
  1030.     UBYTE *argv[MAXARGS];
  1031.     UBYTE argbuf[LINEBUFLEN];
  1032.  
  1033.     /* Parse line */
  1034.     for (len = i = 0; i < MAXARGS - 1; i++) {
  1035.       argv[i] = argbuf + len;
  1036.       item = (short)ReadItem(argbuf + len, sizeof(argbuf) - len, cp);
  1037.       if (item < 0) {
  1038.     logdoserror("ReadItem");
  1039.     return NULL;
  1040.       } else if (item == ITEM_NOTHING) {
  1041.     for (; i < MAXARGS; i++) {
  1042.       argv[i] = " ";
  1043.       len += 2;
  1044.     }
  1045.       } else {
  1046.     len += strlen(argv[i]) + 1;
  1047.       }
  1048.     }
  1049.     if (i == MAXARGS - 1) {
  1050.       argv[i] = cp->CS_Buffer + cp->CS_CurChr;
  1051.       len += strlen(argv[i]) + 1;
  1052.     }
  1053.  
  1054.     sep->se_socktype = FindArg(TYPETEMPLATE, (STRPTR)argv[socket_type]) + 1;
  1055.     if (sep->se_socktype == 0) 
  1056.       sep->se_socktype = DMTYPE_UNKNOWN;
  1057.  
  1058.     switch (FindArg(WAITTEMPLATE, (STRPTR)argv[wait])) {
  1059.     case -1:
  1060.       /* A error message might be cool */
  1061.     case 0:
  1062.       sep->se_wait = DONT_WAIT;
  1063.       break;
  1064.     case 1:
  1065.       sep->se_wait = DO_WAIT;
  1066.       break;
  1067.     }
  1068.  
  1069.     new = malloc(len);
  1070.     if (!new) {
  1071.       SetIoErr(ERROR_NO_FREE_STORE);
  1072.       logdoserror("getconfigent");
  1073.       return NULL;
  1074.     }
  1075.  
  1076.     sep->se_service = new; 
  1077.     old = (char *)argv[service]; while (*new++ = *old++); 
  1078.     sep->se_proto = new;
  1079.     old = (char *)argv[protocol]; while (*new++ = *old++); 
  1080.     sep->se_user = new;
  1081.     old = (char *)argv[user]; while (*new++ = *old++); 
  1082.     sep->se_server = new;
  1083.     old = (char *)argv[server]; while (*new++ = *old++); 
  1084.     sep->se_argv0 = new;
  1085.     old = (char *)argv[cmdname]; while (*new++ = *old++); 
  1086.     sep->se_argv = new;
  1087.     old = (char *)argv[arguments]; while (*new++ = *old++); 
  1088.     /* An empty command line can cause a guru with SASC startup code */
  1089.     if (sep->se_argv[0] == '\0')
  1090.       sep->se_argv = " ";
  1091.   } 
  1092.   
  1093.   if (strcmp(sep->se_server, "internal") == 0) {
  1094.     register struct biltin *bi;
  1095.  
  1096.     for (bi = biltins; bi->bi_service; bi++)
  1097.       if (bi->bi_socktype == sep->se_socktype &&
  1098.       strcmp(bi->bi_service, sep->se_service) == 0)
  1099.     break;
  1100.     if (bi->bi_service == 0) {
  1101.       syslog(LOG_ERR, "inetd: internal service %s unknown\n", sep->se_service);
  1102.       free(sep->se_service);
  1103.       goto more;
  1104.     }
  1105.     sep->se_bi = bi;
  1106.     sep->se_wait = bi->bi_wait;
  1107.   } else
  1108.     sep->se_bi = NULL;
  1109.  
  1110.   return (sep);
  1111. }
  1112.  
  1113. void
  1114. freeconfig(register struct servtab *cp)
  1115. {
  1116.   if (cp->se_service)
  1117.     free(cp->se_service);
  1118. }
  1119.  
  1120. /*
  1121.  * nextline
  1122.  *      get a CSource string containing next line
  1123.  */
  1124. struct CSource *
  1125. nextline(BPTR fh)
  1126. {
  1127.   size_t len = line.CS_Length = 0;
  1128.   UBYTE *buffer = line.CS_Buffer = linbuf;
  1129.   
  1130.   line.CS_CurChr = 0;
  1131.   
  1132.   for (;;) {
  1133.     linecnt++;
  1134.     if (FGets(fh, buffer + len, LINEBUFLEN - len - 1) == NULL) {
  1135.       if (IoErr()) {
  1136.     logdoserror("nextline");
  1137.     return NULL;
  1138.       }
  1139.       if (len == 0)
  1140.     return NULL;
  1141.     }
  1142.  
  1143.     len += strlen(buffer + len);
  1144.     line.CS_Length = len;
  1145.  
  1146.     /* a long line ? */
  1147.     if (len == LINEBUFLEN - 1 && buffer[LINEBUFLEN - 2] != '\n') {
  1148.       if (buffer[0] != '#') {
  1149.     SetIoErr(ERROR_LINE_TOO_LONG);
  1150.     logdoserror("nextline");
  1151.     return NULL;
  1152.       } else {
  1153.     /* A kludge for LONG comment lines */
  1154.     len = 1;
  1155.     linecnt--;
  1156.     continue;
  1157.       }
  1158.     }
  1159.  
  1160.     /* Check for a continued line */
  1161.     if (len > 1 && buffer[len - 2] != '+') {
  1162.       return &line;
  1163.     } else {
  1164.       /* current line continues */
  1165.       if (len > 2)
  1166.     len -= 2;
  1167.       else 
  1168.     len = 0;
  1169.     }
  1170.   }
  1171. }
  1172.  
  1173. /* 
  1174.  * logdoserror
  1175.  *     add the last DOS error into AmiTCP/IP log
  1176.  */
  1177. void 
  1178. logdoserror(const char *banner)
  1179. {
  1180.   LONG code = IoErr();
  1181.  
  1182.   if (linbuf && Fault(code, (UBYTE *)banner, linbuf, LINEBUFLEN)) {
  1183.     syslog(LOG_ERR, "inetd %s at line %ld\n", linbuf, linecnt);
  1184.   } else {
  1185.     syslog(LOG_ERR, "inetd %s: unknown DOS error %ld at line %ld\n", 
  1186.        code, linecnt);
  1187.   }
  1188. }
  1189.  
  1190.  
  1191. /*
  1192.  * Internet services provided internally by inetd:
  1193.  */
  1194.  
  1195. /* Echo service -- echo data back */
  1196. int
  1197. echo_stream(void *SocketBase, int s, struct servtab *sep)
  1198. {
  1199.   char buffer[BUFSIZE];
  1200.   int i;
  1201.  
  1202.   while ((i = recv(s, buffer, sizeof(buffer), 0)) > 0 &&
  1203.      send(s, buffer, i, 0) > 0)
  1204.     ;
  1205.   return 0;
  1206. }
  1207.  
  1208. /* Echo service -- echo data back */
  1209. int
  1210. echo_dg(void *SocketBase, int s, struct servtab *sep)
  1211. {
  1212.   char buffer[BUFSIZE];
  1213.   long i, size;
  1214.   struct sockaddr sa;
  1215.  
  1216.   size = sizeof(sa);
  1217.   if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
  1218.     return 0;
  1219.   (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
  1220.  
  1221.   return 0;
  1222. }
  1223.  
  1224. /* Discard service -- ignore data */
  1225. int
  1226. discard_stream(void *SocketBase, int s, struct servtab *sep)
  1227. {
  1228.   char buffer[BUFSIZE];
  1229.  
  1230.   while (recv(s, buffer, sizeof(buffer), 0) > 0)
  1231.     ;
  1232.  
  1233.   return 0;
  1234. }
  1235.  
  1236.  
  1237. /* Discard service -- ignore data */
  1238. int
  1239. discard_dg(void *SocketBase, int s, struct servtab *sep)
  1240. {
  1241.   char buffer[BUFSIZE];
  1242.  
  1243.   (void) recv(s, buffer, sizeof(buffer), 0);
  1244.   
  1245.   return 0;
  1246. }
  1247.  
  1248. #include <ctype.h>
  1249. #define LINESIZ 72
  1250. char ring[128];
  1251. char *endring = NULL;
  1252.  
  1253. void
  1254. initring(void)
  1255. {
  1256.   register int i;
  1257.  
  1258.   endring = ring;
  1259.  
  1260.   for (i = 0; i <= 128; ++i)
  1261.     if (isprint(i))
  1262.       *endring++ = i;
  1263. }
  1264.  
  1265. /* Character generator */
  1266. chargen_stream(void *SocketBase, int s, struct servtab *sep)
  1267. {
  1268.   register char *rs;
  1269.   long len;
  1270.   char text[LINESIZ+2];
  1271.  
  1272.   if (!endring) {
  1273.     initring();
  1274.     rs = ring;
  1275.   }
  1276.  
  1277.   text[LINESIZ] = '\r';
  1278.   text[LINESIZ + 1] = '\n';
  1279.   for (rs = ring;;) {
  1280.     if ((len = endring - rs) >= LINESIZ)
  1281.       bcopy(rs, text, LINESIZ);
  1282.     else {
  1283.       bcopy(rs, text, len);
  1284.       bcopy(ring, text + len, LINESIZ - len);
  1285.     }
  1286.     if (++rs == endring)
  1287.       rs = ring;
  1288.     if (send(s, text, sizeof(text), 0) != sizeof(text))
  1289.       break;
  1290.   }
  1291.  
  1292.   return 0;
  1293. }
  1294.  
  1295. /* Character generator */
  1296. chargen_dg(void *SocketBase, int s, struct servtab *sep)
  1297. {
  1298.   struct sockaddr sa;
  1299.   static char *rs;
  1300.   long len, size;
  1301.   char text[LINESIZ+2];
  1302.  
  1303.   if (endring == 0) {
  1304.     initring();
  1305.     rs = ring;
  1306.   }
  1307.  
  1308.   size = sizeof(sa);
  1309.   if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
  1310.     return 0;
  1311.  
  1312.   if ((len = endring - rs) >= LINESIZ)
  1313.     bcopy(rs, text, LINESIZ);
  1314.   else {
  1315.     bcopy(rs, text, len);
  1316.     bcopy(ring, text + len, LINESIZ - len);
  1317.   }
  1318.   if (++rs == endring)
  1319.     rs = ring;
  1320.   text[LINESIZ] = '\r';
  1321.   text[LINESIZ + 1] = '\n';
  1322.   (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
  1323.  
  1324.   return 0;
  1325. }
  1326.  
  1327. /*
  1328.  * Return a machine readable date and time, in the form of the
  1329.  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
  1330.  * returns the number of seconds since midnight, Jan 1, 1970,
  1331.  * we must add 2208988800 seconds to this figure to make up for
  1332.  * some seventy years Bell Labs was asleep.
  1333.  */
  1334.  
  1335. long
  1336. machtime(void)
  1337. {
  1338.   struct timeval tv;
  1339.  
  1340.   if (gettimeofday(&tv, (struct timezone *)0) < 0) {
  1341.     /* fprintf(stderr, "Unable to get time of day\n"); */
  1342.     return (0L);
  1343.   }
  1344.   return (htonl((long)tv.tv_sec + 2208988800));
  1345. }
  1346.  
  1347. int 
  1348. machtime_stream(void *SocketBase, int s, struct servtab *sep)
  1349. {
  1350.   long result;
  1351.  
  1352.   result = machtime();
  1353.   (void) send(s, (char *) &result, sizeof(result), 0);
  1354.  
  1355.   return 0;
  1356. }
  1357.  
  1358. machtime_dg(void *SocketBase, int s, struct servtab *sep)
  1359. {
  1360.   long result;
  1361.   struct sockaddr sa;
  1362.   long size;
  1363.  
  1364.   size = sizeof(sa);
  1365.   if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
  1366.     return 0;
  1367.   result = machtime();
  1368.   (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
  1369.  
  1370.   return 0;
  1371. }
  1372.  
  1373. /* Return human-readable time of day */
  1374. int
  1375. daytime_stream(void *SocketBase, int s, struct servtab *sep)
  1376. {
  1377.   char buffer[256];
  1378.   time_t time(), clock;
  1379.   char *ctime();
  1380.   
  1381.   clock = time((time_t *) 0);
  1382.   
  1383.   (void) strncpy(buffer, ctime(&clock), 24);   buffer[24] = '\0';
  1384.   (void) strcat(buffer, "\r\n");
  1385.   (void) send(s, buffer, strlen(buffer), 0);
  1386.   return 0;
  1387. }
  1388.  
  1389. /* Return human-readable time of day */
  1390. int
  1391. daytime_dg(void *SocketBase, int s, struct servtab *sep)
  1392. {
  1393.   char buffer[256];
  1394.   time_t time(), clock;
  1395.   struct sockaddr sa;
  1396.   long size;
  1397.  
  1398.   clock = time((time_t *) 0);
  1399.  
  1400.   size = sizeof(sa);
  1401.   if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
  1402.     return 0;
  1403.  
  1404.   (void) strncpy(buffer, ctime(&clock), 24);   buffer[24] = '\0';
  1405.   (void) strcat(buffer, "\r\n");
  1406.   (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
  1407.   return 0;
  1408. }
  1409.  
  1410. /*
  1411.  * Internal server stub 
  1412.  */
  1413. LONG SAVEDS start_builtin(void)
  1414. {
  1415.   struct Process *me = (struct Process *)FindTask(0L);
  1416.   struct DaemonMessage *dm = (struct DaemonMessage *)me->pr_ExitData;
  1417.   LONG retval = DERR_LIB; 
  1418.   void *SocketBase;
  1419.  
  1420.   if (SocketBase = OpenLibrary("bsdsocket.library", 2L)) {
  1421.     struct servtab *sep = (struct servtab *)dm->dm_Retval;
  1422.     int s = ObtainSocket(dm->dm_Id, AF_INET, sep->se_socktype, 0);
  1423.     if (s != -1) {
  1424.       dm->dm_Id = -1;
  1425.       retval = (*sep->se_bi->bi_fn)(SocketBase, s, sep);
  1426.     } else {
  1427.       retval = DERR_OBTAIN;
  1428.     }
  1429.     CloseLibrary(SocketBase);
  1430.   } 
  1431.  
  1432.   return retval;
  1433. }
  1434.  
  1435. /* 
  1436.  * setproctitle:
  1437.  *      set the process title
  1438.  */
  1439. void
  1440. setproctitle(char *a, int s)
  1441. {
  1442. #ifdef notyet
  1443.   int size;
  1444.   register char *cp;
  1445.   struct sockaddr_in sin;
  1446.   char buf[80];
  1447.   struct CSource csbuf;
  1448.   
  1449.   csbuf.CS_Buffer = buf;
  1450.   csbuf.CS_Length = sizeof(buf) - 1;
  1451.   csbuf.CS_CurChr = 0;
  1452.  
  1453.   size = sizeof(sin);
  1454.   if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) {
  1455.     struct MemList ml, *nml;
  1456.  
  1457.     (void) csprintf(csbuf, "%s [%s]", a, inet_ntoa(sin.sin_addr)); 
  1458.  
  1459.     ml.ml_NumEntries = 1;
  1460.     ml.ml_ME[0].me_Reqs = MEMF_PUBLIC;
  1461.     ml.ml_ME[0].me_Length = csbuf.CS_CurChr + 1;
  1462.  
  1463.     /* A memlist entry is needed for automatic resource deallocation */
  1464.     if ((LONG)(nml = AllocEntry(&ml)) > 0) {
  1465.       struct Task *me = FindTask(NULL);
  1466.  
  1467.       cp = nml->ml_ME[1].me_Addr;
  1468.       buf[csbuf.CS_CurChr] = '\0';
  1469.       strcpy(cp, buf);
  1470.  
  1471.       /* Old name is pointer to se_service, so there is no need to free it */
  1472.       me->tc_Node.ln_Name = cp;
  1473.       Forbid();
  1474.       AddHead(&me->tc_MemEntry, nml);
  1475.       Permit();
  1476.     }
  1477.   }
  1478. #endif
  1479. }
  1480.  
  1481. /* 
  1482.  * proctitle:
  1483.  *     allocate a new process title 
  1484.  */
  1485. UBYTE *
  1486. proctitle(char *a, int s)
  1487. {
  1488.   long size;
  1489.   struct sockaddr_in sin;
  1490.   register char *cp;
  1491.   char buf[80];
  1492.   struct CSource csbuf;
  1493.   
  1494.   csbuf.CS_Buffer = buf;
  1495.   csbuf.CS_Length = sizeof(buf) - 1;
  1496.   csbuf.CS_CurChr = 0;
  1497.  
  1498.   size = sizeof(sin);
  1499.   if (getpeername(s, (struct sockaddr *)&sin, &size) == 0) {
  1500.     (void) csprintf(&csbuf, "%s [%s]", a, inet_ntoa(sin.sin_addr)); 
  1501.   } else {
  1502.     (void) csprintf(&csbuf, "%s", a); 
  1503.   }
  1504.   if (cp = AllocVec(csbuf.CS_CurChr + 1, MEMF_PUBLIC)) {
  1505.     buf[csbuf.CS_CurChr] = '\0';
  1506.     strcpy(cp, buf);
  1507.   }
  1508.   return cp;
  1509. }
  1510.  
  1511. #if __SASC
  1512. #define SysBase (*(struct ExecBase**)4)
  1513. /* 
  1514.  * Amiga process catcher
  1515.  */
  1516. ASM VOID
  1517. exitcode(REG(d0) LONG status, REG(d1) LONG exitmessage)
  1518. {
  1519.   ((struct DaemonMessage *)exitmessage)->dm_Retval = status;
  1520.   ReplyMsg((struct Message *)exitmessage);
  1521. }
  1522.  
  1523. void
  1524. exitcode_end(void)
  1525. {
  1526. }
  1527. #undef SysBase
  1528.  
  1529. #define exitcode_len (((char *)exitcode_end)-((char *)exitcode))
  1530. #else
  1531. #error Unsupported compiler
  1532. #endif
  1533.  
  1534. void *WindowPtr = NULL;
  1535.  
  1536. /* 
  1537.  * Initialize Amiga Specific Features
  1538.  */
  1539. void 
  1540. amigainit(void)
  1541. {
  1542.   struct DaemonPort *dp, *dpo;
  1543.   BYTE msgbit;
  1544.   struct Process *me = (struct Process *)FindTask(NULL);
  1545.   int old_is_alive = 0;
  1546.  
  1547.   atexit(amigadeinit);
  1548.  
  1549.   /* Remove requesters */
  1550.   WindowPtr = me->pr_WindowPtr;
  1551.   me->pr_WindowPtr = (void *)-1L;
  1552.  
  1553.   if ((msgbit = AllocSignal(-1)) == -1) {
  1554.     (void)fprintf(stderr, "inetd: no free signals\n");
  1555.     exit(2);
  1556.   }
  1557.  
  1558.   /* Allocate a global port for DaemonMessages */
  1559.   if (dp = AllocVec(sizeof(*dp) + exitcode_len + sizeof(DAEMONPORTNAME),
  1560.             MEMF_CLEAR|MEMF_PUBLIC)) {
  1561.     dp->dp_Port.mp_Node.ln_Type = NT_MSGPORT;
  1562.     dp->dp_Port.mp_SigTask = me;
  1563.     dp->dp_Port.mp_Flags = PA_SIGNAL;
  1564.     dp->dp_Port.mp_SigBit = msgbit;
  1565.     memcpy(dp->dp_ExitCode = (char *)(dp + 1), exitcode, exitcode_len);
  1566.     memcpy(dp->dp_Port.mp_Node.ln_Name = exitcode_len + (UBYTE *)(dp + 1),
  1567.        DAEMONPORTNAME, sizeof(DAEMONPORTNAME));
  1568.     /* Flush copied function */
  1569.     CacheClearE(dp->dp_ExitCode, exitcode_len, CACRF_ClearI);
  1570.   }
  1571.  
  1572.   Forbid();
  1573.  
  1574.   dpo = (struct DaemonPort*)FindPort(DAEMONPORTNAME);
  1575.   if (!dpo) {
  1576.     if (dp) AddPort(dp);
  1577.   } else {
  1578.     FreeVec(dp);
  1579.     dp = dpo;
  1580.     if (dpo->dp_Port.mp_SigTask == NULL) {
  1581.       dpo->dp_Port.mp_SigTask = me;
  1582.       dpo->dp_Port.mp_SigBit = msgbit;
  1583.       dpo->dp_Port.mp_Flags = PA_SIGNAL;
  1584.       SetSignal(1 << msgbit, 1 << msgbit); /* check old messages */
  1585.     } else {
  1586.       old_is_alive = 1;
  1587.     }
  1588.   }
  1589.   Permit();
  1590.  
  1591.   if (old_is_alive || !dp) {
  1592.     FreeSignal(msgbit);
  1593.     (void)fprintf(stderr, old_is_alive ? 
  1594.           "inetd: already exists\n" :
  1595.           "inetd: memory exhausted\n");
  1596.     exit(2);
  1597.   }
  1598.  
  1599.   dport = dp;
  1600.  
  1601.   if (!(tport = CreateMsgPort())) {
  1602.     (void)fprintf(stderr, "inetd: could not create message port\n");
  1603.     exit(2);
  1604.   }
  1605.   if (!(tmsg = CreateIORequest(tport, sizeof(*tmsg)))){
  1606.     (void)fprintf(stderr, "inetd: could not create timer message\n");
  1607.     exit(2);
  1608.   }
  1609.  
  1610.   tmsg->tr_node.io_Message.mn_Node.ln_Type = NT_UNKNOWN; 
  1611.  
  1612.   if (OpenDevice(TIMERNAME, UNIT_MICROHZ, 
  1613.          (struct IORequest *)tmsg, 0)) {
  1614.     (void)fprintf(stderr, "inetd: could not open %s\n", TIMERNAME);
  1615.     exit(2);
  1616.   }
  1617.   timer_is_open = 1;
  1618. }
  1619.  
  1620. /* 
  1621.  * Deinitialize Amiga Specific stuff
  1622.  */
  1623. void
  1624. amigadeinit(void)
  1625. {
  1626.   struct Process *me = (struct Process *)FindTask(NULL);
  1627.  
  1628.   /* Resume requesters for this process */
  1629.   me->pr_WindowPtr = WindowPtr;
  1630.  
  1631.   if (tmsg && timer_is_open) {
  1632.     if (tmsg->tr_node.io_Message.mn_Node.ln_Type != NT_UNKNOWN 
  1633.     && !CheckIO(tmsg)) {
  1634.       AbortIO(tmsg);
  1635.       WaitIO(tmsg);
  1636.     }
  1637.   }
  1638.   if (timer_is_open) {
  1639.     CloseDevice(tmsg);
  1640.     timer_is_open = 0;
  1641.   }
  1642.   if (tmsg) {
  1643.     DeleteIORequest(tmsg);
  1644.   }
  1645.   if (tport) {
  1646.     DeleteMsgPort(tport);
  1647.   }
  1648.  
  1649.   if (dport) {
  1650.     BYTE sigbit;
  1651.     int i;
  1652.  
  1653.     /* Try to kill all our builtin children */
  1654.     for (i = builtins_started - 1; i >= 0; i--)
  1655.       Signal((struct Task*)ptable[i], SIGBREAKF_CTRL_C);
  1656.     /* Close all sockets */
  1657.     for (i = NOFILE - 1; i >= 0; i--) {
  1658.       CloseSocket(i);
  1659.     }
  1660.     /* Wait until all childs are terminated */
  1661.     while (builtins_started > 0) {
  1662.       WaitPort(dport);
  1663.       reapchild();
  1664.     }
  1665.  
  1666.     Forbid();
  1667.     sigbit = dport->dp_Port.mp_SigBit;
  1668.     dport->dp_Port.mp_Flags = PA_IGNORE;
  1669.     dport->dp_Port.mp_SigBit = (UBYTE)-1; /* braindead */
  1670.     dport->dp_Port.mp_SigTask = NULL;
  1671.     FreeSignal(sigbit);
  1672.     Permit();
  1673.   }
  1674. }
  1675.  
  1676. /*
  1677.  * Generic printing functions 
  1678.  */
  1679. void ASM 
  1680. stuffchar(REG(d0) char ch, REG(a3) struct CSource * sc)
  1681. {
  1682.   if (sc->CS_CurChr < sc->CS_Length 
  1683.       && (sc->CS_Buffer[sc->CS_CurChr] = ch))
  1684.     sc->CS_CurChr++;
  1685. }
  1686.  
  1687. static ULONG
  1688. csprintf(struct CSource *buf, const char *fmt, ...)
  1689. {
  1690.   ULONG start = buf->CS_CurChr;
  1691.   va_list ap;
  1692.  
  1693.   if (buf->CS_Length && buf->CS_CurChr < buf->CS_Length) {
  1694.     va_start(ap, fmt);
  1695.     RawDoFmt((STRPTR)fmt, ap, stuffchar, buf);
  1696.     va_end(ap);
  1697.     
  1698.     if (buf->CS_CurChr == buf->CS_Length) {
  1699.       buf->CS_CurChr--;            /* must NUL terminate */
  1700.     }      
  1701.     buf->CS_Buffer[buf->CS_CurChr] = '\0';
  1702.  
  1703.     return buf->CS_CurChr - start;
  1704.   } else {
  1705.     /* A pathological case */
  1706.     return 0;
  1707.   }
  1708. }
  1709.